﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CommonLibrary.Helpers;
using ShuntingScheduleUserControl.Helper;
using ShuntingScheduleUserControl.Model;
using ShuntingScheduleUserControl.View;
using CommonLibrary.Models;
using FileLibrary;
using FileLibrary.Enums;
using FileLibrary.Models;

namespace ShuntingScheduleUserControl
{
    /// <summary>
    /// 基于JobId，MachId，ProcId，StartTime，EndTime格式的自定义控件
    /// 显示调度方案
    /// </summary>
    public partial class MainUserControl : UserControl
    {
        public event EventHandler AutoCalClick;

        //横坐标
        private List<Node> Nodes = new List<Node>();

        private List<ViewNode> ViewNodes = new List<ViewNode>();

        //public List<int> AllTimesOfA { get; set; } = new List<int>();
        //public List<int> AllTimesOfB { get; set; } = new List<int>();
        //public List<int> AllTimesOfBToA { get; set; } = new List<int>();

        private Dictionary<int, ViewTrain> ViewShuntingScheduleByJobIds { get; set; } = new Dictionary<int, ViewTrain>();

        private readonly DrawContext drawContext;

        private DrawContext DrawContext => drawContext;

        public MainUserControl()
        {
            InitializeComponent();
            drawContext = new DrawContext();
        }

        /// <summary>
        /// 必须接入股道信息及调车信息
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="shuntingSchedules"></param>
        public void InitData(List<Schedule> shuntingSchedules)
        {
            Nodes = GetNodes();
            InitViewNodes();
            ViewShuntingScheduleByJobIds.Clear();

            var shuntingSchedulesByJobId = shuntingSchedules?.OrderBy(x => x.StartTime + x.EndTime).GroupBy(z => z.JobId);
            if (shuntingSchedulesByJobId == null) return;
            foreach (var pair in shuntingSchedulesByJobId)
            {
                var key = pair.Key;
                var list = pair.ToList();
                var tmp = new ViewTrain(key, list, drawContext);
                ViewShuntingScheduleByJobIds.Add(key, tmp);
            }
        }

        public List<Node> GetNodes()
        {
            var nodes = new List<Node>();
            var tracks = FileManage.Instance.FileModes.Values.Where(x => x is Track).Cast<Track>().ToList();
            foreach (TrackTypeEnum value in Enum.GetValues(typeof(TrackTypeEnum)))
            {
                var str = EnumsHelper.GetDescriptionAttribute(value);
                nodes.AddRange(from track in tracks where track.TrackTypeStr == str select new Node { Index = track.Index, TrackTypeEnum = value, Name = track.Name, TrackPosEnum = track.TrackPosEnum });
            }

            return nodes;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var g = e.Graphics;
            var rec = ClientRectangle;

            DrawNodes(g, rec);
            DrawBackground(g, rec);
            DrawShuntingSchedules(g, rec);

            base.OnPaint(e);
        }

        private void DrawBackground(Graphics g, Rectangle rec)
        {
            //  -------------
            // |             | TimeWordsWidth
            //  -------------
            // NodeWordsWidth

            var NodeWordsWidth = DrawContext.NodeWordsWidth;
            var TimeWordsWidth = DrawContext.TimeWordsWidth;
            var HourWidth = DrawContext.HourWidth;
            var PlanStartMinuteCnt = DrawContext.PlanStartMinuteCnt;
            var PlanStopMinuteCnt = DrawContext.PlanStopMinuteCnt;

            g.DrawLine(DrawHelper.PenBlack1, NodeWordsWidth, rec.Top, NodeWordsWidth, rec.Bottom); //竖线
            g.DrawLine(DrawHelper.PenBlack1, NodeWordsWidth / 2, rec.Top, NodeWordsWidth / 2, rec.Bottom); //竖线，股道分类和名称中间
            g.DrawLine(DrawHelper.PenBlack1, rec.Left, TimeWordsWidth, rec.Right, TimeWordsWidth); //横线
            g.FillRectangle(DrawHelper.BrushNodeNameBackground, new RectangleF(rec.Left, rec.Top, NodeWordsWidth, TimeWordsWidth));
            var date = $"{DateTime.Now:yyyy年MM月dd日}";
            var wordWidth = g.MeasureString(date, DrawHelper.FtDefault).Width;
            g.DrawString(date, DrawHelper.FtDefault, DrawHelper.BrushNodeName, new RectangleF(rec.Left + (NodeWordsWidth - wordWidth) / 2, rec.Top + TimeWordsWidth / 3, NodeWordsWidth, TimeWordsWidth));
            var start = PlanStartMinuteCnt;
            var stop = PlanStopMinuteCnt < PlanStartMinuteCnt ? PlanStopMinuteCnt + 24 : PlanStopMinuteCnt;
            for (int i = start; i <= stop; i++)
            {
                var xHour = NodeWordsWidth + (i - start) * HourWidth;
                var xHalfHour = NodeWordsWidth + (i - start) * HourWidth + HourWidth / 2;
                g.DrawLine(DrawHelper.PenBlack1, xHour, rec.Top, xHour, TimeWordsWidth); //小时线
                g.DrawLine(DrawHelper.PenBlack1, xHalfHour, TimeWordsWidth * 2 / 3, xHalfHour, TimeWordsWidth); //小时线
                g.DrawString($"{i % 24:D2}:00", DrawHelper.FtDefault, DrawHelper.BrushTimeName, new RectangleF(xHour, rec.Top + TimeWordsWidth / 3, HourWidth, TimeWordsWidth));
            }

            g.DrawRectangle(DrawHelper.PenBlue5, rec);
        }

        private void DrawShuntingSchedules(Graphics g, Rectangle rec)
        {
            foreach (var value in ViewShuntingScheduleByJobIds.Values)
            {
                value.Draw(g, rec);
            }
        }

        private void DrawNodes(Graphics g, Rectangle rec)
        {
            if (Nodes == null) return;
            DrawViewNodes(g, rec);
            DrawDescription(g, rec, ClientRectangle.Left + drawContext.NodeWordsWidth / 2);
        }
        /// <summary>
        /// 绘制一类股道的下划线和左侧文字描述
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rec"></param>
        /// <param name="nodeWordsLeft"></param>
        private void DrawDescription(Graphics g, Rectangle rec, int nodeWordsLeft)
        {
            var NodeWordsWidth = drawContext.NodeWordsWidth;
            var TimeWordsWidth = drawContext.TimeWordsWidth;
            var NodeHeight = drawContext.NodeHeight;

            var descriptionStart = TimeWordsWidth;
            var descriptionStop = TimeWordsWidth;
            foreach (TrackTypeEnum nodeTypeEnum in System.Enum.GetValues(typeof(TrackTypeEnum)))
            {
                var nodes = Nodes.Where(x => x.TrackTypeEnum == nodeTypeEnum).ToList();
                var height = nodes.Count * NodeHeight; //股道总高度
                descriptionStop += height;
                g.DrawLine(DrawHelper.PenBlack1, rec.Left, descriptionStop, nodeWordsLeft, descriptionStop);

                var fieldInfo = typeof(TrackTypeEnum).GetField(nodeTypeEnum.ToString());
                var description = Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (description != null)
                {
                    var size = g.MeasureString(description.Description, DrawHelper.FtNodeName);
                    g.DrawString(description.Description, DrawHelper.FtNodeName, DrawHelper.BrushTimeName,
                        new PointF(rec.Left + ((float)NodeWordsWidth / 2 - size.Width) / 2,
                            (float)(descriptionStart + descriptionStop - size.Height) / 2));
                }

                descriptionStart += height;
            }
        }
        /// <summary>
        /// 绘制股道线及股道名
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rec"></param>
        private void DrawViewNodes(Graphics g, Rectangle rec)
        {
            foreach (var viewNode in ViewNodes)
            {
                viewNode.Draw(g, rec);
            }
        }

        private int InitViewNodes()
        {
            var NodeWordsWidth = drawContext.NodeWordsWidth;
            var TimeWordsWidth = drawContext.TimeWordsWidth;
            var NodeHeight = drawContext.NodeHeight;
            var HourWidth = drawContext.HourWidth;

            var nodeWordsLeft = ClientRectangle.Left + NodeWordsWidth / 2;
            if (ViewNodes.Count != 0) return nodeWordsLeft;
            for (int i = 0; i < Nodes.Count; i++)
            {
                var node = Nodes[i];
                var nodeWordsBottom = TimeWordsWidth + (i + 1) * NodeHeight;
                var nodeWordsTop = TimeWordsWidth + i * NodeHeight;
                var viewNode = new ViewNode(node, drawContext)
                {
                    //MachId = node.Index - minNode,
                    MachId = node.Index,
                    Bottom = nodeWordsBottom,
                    Top = nodeWordsTop,
                    Left = nodeWordsLeft,
                    Middle = (nodeWordsTop + nodeWordsBottom) / 2,
                    TimeLeft = ClientRectangle.Left + NodeWordsWidth,

                };

                drawContext.NodeYDictionary.Add(node.Index, (float)(nodeWordsBottom + nodeWordsTop) / 2);
                ViewNodes.Add(viewNode);
            }

            this.Size = new Size(NodeWordsWidth + (drawContext.PlanStopMinuteCnt - drawContext.PlanStartMinuteCnt + 24) * HourWidth, TimeWordsWidth + Nodes.Count * NodeHeight);
            return nodeWordsLeft;
        }

        public void InitData(List<int> allTimesOfA, List<int> allTimesOfB, List<int> allTimesOfBToA)
        {
            //AllTimesOfA = allTimesOfA;
            //AllTimesOfB = allTimesOfB;
            //AllTimesOfBToA = allTimesOfBToA;

            //AllTimesOfA.Sort();
            //AllTimesOfB.Sort();
        }

        private void MainUserControl_DoubleClick(object sender, EventArgs e)
        {
            //var form = new ThroatUsingInfoForm();
            //foreach (var shuntingScheduleId in shuntingSchedulesByJobId)
            //{
            //    var list = shuntingScheduleId.ToList();
            //    foreach (var shuntingSchedule in list)
            //    {
            //        if (AllTimesOfA.Contains(shuntingSchedule.StartTime))
            //        {
            //            form.ThroatUsingInfos.Add(new ThroatUsingInfo() { ThroatName = "A", TrainName = shuntingSchedule.JobId, UseTime = shuntingSchedule.StartTime.GetDateTimeByMinute() });
            //        }

            //        if (AllTimesOfA.Contains(shuntingSchedule.EndTime))
            //        {
            //            form.ThroatUsingInfos.Add(new ThroatUsingInfo() { ThroatName = "A", TrainName = shuntingSchedule.JobId, UseTime = shuntingSchedule.EndTime.GetDateTimeByMinute() });
            //        }

            //        if (AllTimesOfB.Contains(shuntingSchedule.EndTime))
            //        {
            //            form.ThroatUsingInfos.Add(new ThroatUsingInfo() { ThroatName = "B", TrainName = shuntingSchedule.JobId, UseTime = shuntingSchedule.EndTime.GetDateTimeByMinute() });
            //        }
            //    }
            //}

            //form.ShowDialog();
        }

        private void 连接线ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DrawContext.DrawConnectionLine = !DrawContext.DrawConnectionLine;
            连接线ToolStripMenuItem.Checked = DrawContext.DrawConnectionLine;
            Invalidate();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                contextMenuStrip1.Show(this, e.Location);
            }
            else
            {
                var list = ViewShuntingScheduleByJobIds.Values.Where(x => x.IsInRange(e.Location)).Select(y => y.JobId).ToList();
                foreach (var viewTrain in ViewShuntingScheduleByJobIds.Values)
                {
                    viewTrain.IsShow = list.Count <= 0 || list.Contains(viewTrain.JobId);
                }

                Invalidate();
            }

            base.OnMouseUp(e);
        }

        private void 列位线ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DrawContext.DrawPosLine = !DrawContext.DrawPosLine;
            列位线ToolStripMenuItem.Checked = DrawContext.DrawPosLine;
            Invalidate();
        }

        private void MainUserControl_Load(object sender, EventArgs e)
        {
            if (DesignMode)
            {
                return;
            }

            Nodes = GetNodes();
            InitViewNodes();
        }

        private void 自动计算ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AutoCalClick?.Invoke(sender, e);
        }

        private void 调车计划列表ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var form = new ScheduleListForm(ViewShuntingScheduleByJobIds);
            form.ShowDialog(this);
        }
    }
}
